package com.service.Impl;

import com.dto.OrderDto;
import com.dto.OrderItemDto;
import com.entity.*;
import com.exception.AddException;
import com.exception.DateNotFoundException;
import com.exception.DeleteException;
import com.exception.UpdateException;
import com.github.pagehelper.PageInfo;
import com.mapper.*;
import com.service.OrderService;
import com.utils.OrderNoGenerator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 *@ClassName OrderServiceImpl
 *@Description  订单业务层实现类
 *@Author Kx
 *@Date 2025/5/27 19:45
 *@Version 1.0
 */
@Service("orderService")
public class OrderServiceImpl implements OrderService {

    private final OrderMapper orderMapper;
    private final ProductMapper productMapper;
    private final UserMapper userMapper;
    private final UserCouponMapper userCouponMapper;
    private final CouponMapper couponMapper;

    public OrderServiceImpl(OrderMapper orderMapper, ProductMapper productMapper, UserMapper userMapper, UserCouponMapper userCouponMapper, CouponMapper couponMapper) {
        this.orderMapper = orderMapper;
        this.productMapper = productMapper;
        this.userMapper = userMapper;
        this.userCouponMapper = userCouponMapper;
        this.couponMapper = couponMapper;
    }

    /**
     * @author: kx
     * @date: 2025/6/3 11:42
     * @param order : 订单信息
     * @param orderItems : 订单项信息
     * @description: 处理订单核心逻辑
    */
    private void processOrderCoreLogic(Order order, List<OrderItem> orderItems) {
        // 生成订单编号
        String orderId = OrderNoGenerator.generateOrderNo();
        // 设置订单编号
        order.setOrderId(orderId);
        // 设置创建时间
        order.setCreateTime(new Date());

        // 计算总金额
        BigDecimal totalAmount = calculateTotalAmount(orderItems);

        // 验证库存并扣减
        validateAndUpdateStock(orderItems);

        // 设置原始金额
        order.setOriginalAmount(totalAmount);

        // 处理优惠券
        processCoupon(order, totalAmount);

        // 添加订单信息
        try {
            orderMapper.addOrder(order);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AddException(1002, "添加订单失败");
        }
    }

    /**
     * @author: kx
     * @date: 2025/6/3 11:46
     * @param orderItems : 订单项信息
     * @return java.math.BigDecimal
     * @description: 计算总金额
    */
    private BigDecimal calculateTotalAmount(List<OrderItem> orderItems) {
        return orderItems.stream()
                .map(orderItem -> {
                    // 查询商品信息
                    Product product = productMapper.findById(orderItem.getProductId());
                    return product.getPrice().multiply(BigDecimal.valueOf(orderItem.getQuantity()));
                })
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * @author: kx
     * @date: 2025/6/3 11:48
     * @param orderItems : 订单项信息
     * @description: 验证商品库存是否充足并且修改库存
    */
    private void validateAndUpdateStock(List<OrderItem> orderItems) {
        for (OrderItem orderItem : orderItems) {
            // 查询商品信息
            Product product = productMapper.findById(orderItem.getProductId());

            // 验证库存
            if (product.getNumber() < orderItem.getQuantity()) {
                throw new DateNotFoundException(1001, "商品数量不足");
            }

            // 扣减库存
            try {
                productMapper.updateProductNumber(orderItem.getProductId(), orderItem.getQuantity());
            } catch (Exception e) {
                e.printStackTrace();
                throw new UpdateException(1003, "修改商品数量失败");
            }
        }
    }

    /**
     * @author: kx
     * @date: 2025/6/3 11:49
     * @param order : 订单信息
     * @param originalAmount : 原始金额
     * @description: 处理优惠券逻辑(计算优惠后的金额)
    */
    private void processCoupon(Order order, BigDecimal originalAmount) {
        if (order.getCouponId() == null) {
            // 未使用优惠券
            order.setPaymentAmount(originalAmount);
            return;
        }

        // 标记优惠券为已使用
        UserCoupon userCoupon = new UserCoupon();
        userCoupon.setUserId(order.getUserId());
        userCoupon.setCouponId(order.getCouponId());
        userCoupon.setOrderId(order.getOrderId());
        userCoupon.setUsedTime(LocalDateTime.now());

        try {
            userCouponMapper.updateUserCoupon(userCoupon);
        } catch (Exception e) {
            throw new UpdateException(1003, "修改用户优惠券状态失败");
        }

        // 计算优惠后金额
        Coupon coupon = couponMapper.findById(order.getCouponId());
        BigDecimal paymentAmount = calculateDiscountedPrice(originalAmount, coupon);

        // 设置优惠金额和实际支付金额
        order.setDiscountAmount(originalAmount.subtract(paymentAmount));
        order.setPaymentAmount(paymentAmount);
    }

    /**
     * @author: kx
     * @date: 2025/6/3 11:52
     * @param originalAmount : 原始金额
     * @param coupon : 优惠券信息
     * @return java.math.BigDecimal
     * @description: 计算使用各种优惠券后的金额
    */
    private BigDecimal calculateDiscountedPrice(BigDecimal originalAmount, Coupon coupon) {
        switch (coupon.getType()) {
            case 1: // 满减券
                return originalAmount.compareTo(coupon.getMinimumAmount()) >= 0
                        ? originalAmount.subtract(coupon.getAmount())
                        : originalAmount;
            case 2: // 折扣券
                return originalAmount.multiply(coupon.getDiscountRate());
            case 3: // 无门槛券
                return originalAmount.subtract(coupon.getAmount());
            default:
                return originalAmount;
        }
    }

    /**
     * @param order      : 订单信息
     * @param orderItemList : 订单商品集合
     * @author: kx
     * @date: 2025/5/27 19:46
     * @description: 添加订单信息(通过购物车方式购买)
     */
    @Transactional
    @Override
    public synchronized void addOrderTrolley(Order order, List<OrderItem> orderItemList) {
        // 处理订单核心逻辑
        processOrderCoreLogic(order, orderItemList);

        for (OrderItem orderItem : orderItemList) {
            // 设置订单编号
            orderItem.setOrderId(order.getOrderId());
            try {
                // 修改订单商品信息
                orderMapper.updateOrderItem(orderItem);
            } catch (Exception e) {
                throw new UpdateException(1003, "修改订单商品项信息失败");
            }
        }
    }

    /**
     * @author: kx
     * @date: 2025/6/3 9:45
     * @param order : 订单信息
     * @param orderItems : 订单商品信息集合
     * @description: 添加订单(直接购买商品不通过购物车)
    */
    @Transactional
    @Override
    public void addOrder(Order order, List<OrderItem> orderItems) {

        // 处理订单核心逻辑
        processOrderCoreLogic(order, orderItems);

        for (OrderItem orderItem : orderItems) {
            // 设置订单编号
            orderItem.setOrderId(order.getOrderId());

            try {
                // 添加订单商品信息
                orderMapper.addOrderItem(orderItem);
            } catch (Exception e) {
                e.printStackTrace();
                throw new AddException(1001, "添加订单商品项信息失败");
            }
        }
    }

    /**
     * @author: kx
     * @date: 2025/5/27 19:53
     * @param orderItem : 订单商品项信息
     * @description: 添加订单商品项信息
    */
    @Transactional
    @Override
    public void addOrderItem(OrderItem orderItem) {
        try {
            orderMapper.addOrderItem(orderItem);
        } catch (Exception e) {
            throw new AddException(10001, "添加订单商品项信息失败");
        }
    }

    /**
     * @author: kx
     * @date: 2025/5/28 10:33
     * @param userId : 用户编号
     * @return java.util.List<com.entity.OrderItem>
     * @description: 根据用户编号查询购物车信息
    */
    @Override
    public List<OrderItemDto> findByUserId(Integer userId) {
        List<OrderItemDto> list = new ArrayList<>();
        List<OrderItem> orderItemList = orderMapper.findByUserId(userId);

        for (OrderItem orderItem : orderItemList) {
            // 创建数据传输对象
            OrderItemDto orderItemDto = new OrderItemDto();
            // 设置订单
            orderItemDto.setOrderItem(orderItem);
            // 根据商品编号查询商品信息
            Product product = productMapper.findById(orderItem.getProductId());
            // 设置商品
            orderItemDto.setProduct(product);
            // 添加到集合中
            list.add(orderItemDto);
        }
        return list;
    }

    /**
     * @author: kx
     * @date: 2025/5/28 10:53
     * @param orderItem : 订单商品信息
     * @description: 修改订单商品信息
    */
    @Transactional
    @Override
    public void updateOrderItem(OrderItem orderItem) {
        try {
            orderMapper.updateOrderItem(orderItem);
        } catch (Exception e) {
            throw new UpdateException(1003, "修改订单商品信息失败");
        }
    }

    /**
     * @author: kx
     * @date: 2025/5/28 11:10
     * @param itemId : 订单商品id
     * @description: 删除订单商品信息
    */
    @Transactional
    @Override
    public void deleteOrderItem(Integer itemId) {
        try {
            orderMapper.deleteOrderItem(itemId);
        } catch (Exception e) {
            throw new DeleteException(1004, "删除订单商品信息失败");
        }
    }

    /**
     * @author: kx
     * @date: 2025/5/28 15:03
     * @param orderStatus : 订单状态
     * @param userId : 用户id
     * @return java.util.List<com.dto.OrderDto>
     * @description: 根据订单状态查询和用户编号订单信息
    */
    @Override
    public List<OrderDto> findByOrderStatus(Integer orderStatus, Integer userId) {
        List<OrderDto> orderDtoList = new ArrayList<>();
        // 查询所有订单信息
        List<Order> orderList = orderMapper.findByOrderStatus(orderStatus, userId);
        for (Order order : orderList) {
            List<OrderItemDto> orderItemDtoList = new ArrayList<>();
            OrderDto orderDto = new OrderDto();
            // 封装订单信息
            orderDto.setOrder(order);
            // 查询订单用户信息
            User user = userMapper.selectUserInfoByAccountId(userId);
            // 封装用户信息
            orderDto.setUser(user);
            // 查询订单项信息
            List<OrderItem> orderItemList = orderMapper.findByOrderId(order.getOrderId());
            for (OrderItem orderItem : orderItemList) {
                OrderItemDto orderItemDto = new OrderItemDto();
                // 封装订单商品项信息
                orderItemDto.setOrderItem(orderItem);
                // 查询订单项商品信息
                Product product = productMapper.findById(orderItem.getProductId());
                // 封装商品信息
                orderItemDto.setProduct(product);
                // 把订单商品项信息添加到集合中
                orderItemDtoList.add(orderItemDto);
            }
            // 封装订单商品项信息
            orderDto.setOrderItemDtoS(orderItemDtoList);
            // 把订单信息添加到集合中
            orderDtoList.add(orderDto);
        }
        return orderDtoList;
    }

    /**
     * @author: kx
     * @date: 2025/5/28 16:02
     * @param orderId : 订单id
     * @param orderStatus : 订单状态
     * @param cancelReason : 取消原因
     * @description: 根据订单编号修改订单状态
    */
    @Transactional
    @Override
    public void updateOrderStatus(String orderId, Integer orderStatus, String cancelReason) {
        try {
            Order order = new Order();
            //设置订单编号
            order.setOrderId(orderId);
            // 设置订单状态
            order.setOrderStatus(orderStatus);
            // 判断是否是支付
            if (orderStatus == 1) {
                // 设置支付时间
                order.setPayTime(new Date());
            } else if (orderStatus == 5) {
                // 设置取消原因
                order.setCancelReason(cancelReason);
            }
            orderMapper.updateOrderStatus(order);
        } catch (Exception e) {
            e.printStackTrace();
            throw new UpdateException(1003, "修改订单状态失败");
        }
    }

    /**
     * @param orderId : 订单编号
     * @return com.entity.Order
     * @author: kx
     * @date: 2025/6/4 9:01
     * @description: 根据订单编号查询订单信息
     */
    @Override
    public Order getOrderById(String orderId) {
        // 获取订单信息
        Order order = orderMapper.getOrderById(orderId);
        if (order != null) {
            return order;
        }
        throw new DateNotFoundException(1001, "订单信息不存在");
    }

    /**
     * @author: kx
     * @date: 2025/6/11 9:11
     * @param yearMonth : 年月份
     * @return java.math.BigDecimal
     * @description: 根据年月份查询该年月份的销售额
    */
    @Override
    public BigDecimal findSalesByYearAndMonth(String yearMonth) {
        if (orderMapper.findSalesByYearAndMonth(yearMonth) != null) {
            return orderMapper.findSalesByYearAndMonth(yearMonth);
        }
        throw new DateNotFoundException(1001, "没有查询到该月份的销售额");
    }

    /**
     * @author: kx
     * @date: 2025/6/11 20:21
     * @param year : 年份
     * @return java.util.Map<java.lang.Integer,java.math.BigDecimal>
     * @description: 根据年份查询该年份的每个月的销售额
    */
    @Override
    public Map<Integer, BigDecimal> getMonthlySalesByYear(String year) {
        if (orderMapper.getMonthlySalesByYear(year) != null) {
            return orderMapper.getMonthlySalesByYear(year);
        }
        throw new DateNotFoundException(1001,"没有查询该年份的每个月的销售额");
    }

    /**
     * @author: kx
     * @date: 2025/6/16 15:40
     * @param pageNum : 页码
     * @param pageSize : 每页显示的条数
     * @return com.github.pagehelper.PageInfo<com.entity.Order>
     * @description: 分页查询所有订单信息
    */
    @Override
    public PageInfo<OrderDto> findAllOrders(int pageNum, int pageSize) {
        if (!orderMapper.findAllOrders(pageNum, pageSize).isEmpty()) {
            // 获取所有订单信息
            List<Order> orderList = orderMapper.findAllOrders(pageNum, pageSize);
            // 创建订单传输对象集合
            List<OrderDto> orderDtoList = new ArrayList<>();
            for (Order order : orderList) {
                // 创建订单商品项传输对象集合
                List<OrderItemDto> orderItemDtoList = new ArrayList<>();
                OrderDto orderDto = new OrderDto();
                // 设置订单信息
                orderDto.setOrder(order);
                User user = userMapper.findByUserId(order.getUserId());
                if (user == null) {
                    throw new DateNotFoundException(1001, "没有查询到该用户信息");
                }
                // 设置用户信息
                orderDto.setUser(user);
                // 获取订单商品项信息
                List<OrderItem> orderItemList = orderMapper.findByOrderId(order.getOrderId());
                if (orderItemList.isEmpty()) {
                    throw new DateNotFoundException(1001, "没有查询到该订单商品项信息");
                }
                for (OrderItem orderItem : orderItemList) {
                    OrderItemDto orderItemDto = new OrderItemDto();
                    // 设置订单商品项信息
                    orderItemDto.setOrderItem(orderItem);
                    // 获取商品信息
                    Product product = productMapper.findById(orderItem.getProductId());
                    if (product == null) {
                        throw new DateNotFoundException(1001, "没有查询到该商品信息");
                    }
                    // 设置商品信息
                    orderItemDto.setProduct(product);
                    // 添加到集合中
                    orderItemDtoList.add(orderItemDto);
                }
                // 设置订单商品项传输对象集合
                orderDto.setOrderItemDtoS(orderItemDtoList);
                // 添加到集合中
                orderDtoList.add(orderDto);
            }
            return new PageInfo<>(orderDtoList);
        }
        throw new DateNotFoundException(1001, "没有查询到所有订单信息");
    }

    /**
     * @author: kx
     * @date: 2025/6/19 15:37
     * @param userKeyword : 用户名关键词
     * @param pageNum : 页码
     * @param pageSize : 每页显示的条数
     * @return com.github.pagehelper.PageInfo<com.dto.OrderDto>
     * @description: 根据用户名关键词分页查询用户订单信息
    */
    @Override
    public PageInfo<OrderDto> findOrdersByUserId(String userKeyword, int pageNum, int pageSize) {
        if (!orderMapper.searchOrdersByUserKeyword(userKeyword, pageNum, pageSize).isEmpty()) {
            // 获取订单信息
            List<Order> orderList = orderMapper.searchOrdersByUserKeyword(userKeyword, pageNum, pageSize);
            // 创建订单传输对象集合
            List<OrderDto> orderDtoList = new ArrayList<>();
            for (Order order : orderList) {
                // 创建订单商品项传输对象集合
                List<OrderItemDto> orderItemDtoList = new ArrayList<>();
                // 创建订单传输对象
                OrderDto orderDto = new OrderDto();
                // 设置订单信息
                orderDto.setOrder(order);
                // 获取用户信息
                User user = userMapper.findByUserId(order.getUserId());
                if (user == null) {
                    throw new DateNotFoundException(1001, "没有查询到该用户信息");
                }
                // 设置用户信息
                orderDto.setUser(user);
                // 获取订单商品项信息
                List<OrderItem> orderItemList = orderMapper.findByOrderId(order.getOrderId());
                if (orderItemList.isEmpty()) {
                    throw new DateNotFoundException(1001, "没有查询到该订单商品项信息");
                }
                for (OrderItem orderItem : orderItemList) {
                    // 创建订单商品项传输对象
                    OrderItemDto orderItemDto = new OrderItemDto();
                    // 设置订单商品项信息
                    orderItemDto.setOrderItem(orderItem);
                    // 获取商品信息
                    Product product = productMapper.findById(orderItem.getProductId());
                    if (product == null) {
                        throw new DateNotFoundException(1001, "没有查询到该商品信息");
                    }
                    // 设置商品信息
                    orderItemDto.setProduct(product);
                    // 添加到集合中
                    orderItemDtoList.add(orderItemDto);
                }
                // 设置订单商品项传输对象集合
                orderDto.setOrderItemDtoS(orderItemDtoList);
                // 添加到集合中
                orderDtoList.add(orderDto);
            }
            return new PageInfo<>(orderDtoList);
        }
        throw new DateNotFoundException(1001, "没有查询到该用户订单信息");
    }
}
